use std::{collections::HashMap, hash::Hash, marker::PhantomData};

pub trait ChannelId: Clone + PartialEq + Eq + Hash {}

pub trait UserInfo: Clone {}

pub trait NodeAddr: Clone {
    fn deserialize(buf: &NodeIdBuffer) -> Self;

    fn serialize(&self, buf: &mut NodeIdBuffer);
}

pub struct Node<ChannelIdImpl: ChannelId, UserInfoImpl: UserInfo, NodeAddrImpl: NodeAddr> {
    id: NodeId<NodeAddrImpl>,
    bootstrap: bool,
    buckets: Vec<Bucket<ChannelIdImpl, UserInfoImpl, NodeAddrImpl>>,
}

#[derive(Clone)]
struct Bucket<ChannelIdImpl: ChannelId, UserInfoImpl: UserInfo, NodeAddrImpl: NodeAddr> {
    nodes: HashMap<NodeId<NodeAddrImpl>, NodeInfo<ChannelIdImpl, UserInfoImpl, NodeAddrImpl>>,
    nodes_max: usize,
}

impl<ChannelIdImpl: ChannelId, UserInfoImpl: UserInfo, NodeAddrImpl: NodeAddr> Default
    for Bucket<ChannelIdImpl, UserInfoImpl, NodeAddrImpl>
{
    fn default() -> Self {
        Self {
            nodes: HashMap::new(),
            nodes_max: 128,
        }
    }
}

impl<ChannelIdImpl: ChannelId, UserInfoImpl: UserInfo, NodeAddrImpl: NodeAddr>
    Node<ChannelIdImpl, UserInfoImpl, NodeAddrImpl>
{
    pub fn new(id: NodeId<NodeAddrImpl>, is_root: bool) -> Self {
        Self {
            id,
            bootstrap: is_root,
            buckets: vec![Default::default(); ID_BITS_SIZE],
        }
    }

    pub fn is_bootstrap(&self) -> bool {
        self.bootstrap
    }

    pub fn input_message(
        &mut self,
        msg: Option<(ChannelIdImpl, Message)>,
    ) -> (Option<(ChannelIdImpl, Message)>, Option<Response>) {
        todo!()
    }
}

#[derive(Clone, Debug)]
pub struct Message {}


pub const ID_BITS_SIZE: usize = 256;

#[derive(Clone)]
struct NodeInfo<ChnId: ChannelId, UsrInfo: UserInfo, Addr: NodeAddr> {
    id: NodeId<Addr>,
    channels: Vec<ChnId>,
    user_info: UsrInfo,
}

#[derive(Clone, Debug)]
pub struct Response {}

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct NodeId<Addr: NodeAddr> {
    buf: NodeIdBuffer,
    _ph: PhantomData<Addr>,
}

impl<Addr: NodeAddr> NodeId<Addr> {}

impl<Addr: NodeAddr> From<Addr> for NodeId<Addr> {
    fn from(addr: Addr) -> Self {
        let mut buf = NodeIdBuffer::default();
        addr.serialize(&mut buf);

        Self {
            buf,
            _ph: Default::default(),
        }
    }
}

impl<Addr: NodeAddr> From<&[u8]> for NodeId<Addr> {
    fn from(buf: &[u8]) -> Self {
        todo!()
    }
}

type NodeIdBuffer = [u8; ID_BITS_SIZE / 8];
